#include <iostream>
#include <fstream>
#include <cstdio>
#include <string.h>
#include <cstdlib>
#include <time.h>

using namespace std;

typedef unsigned char uchar;

typedef struct {
	float red,blue,green;
}PPMPixel;

typedef struct {
	unsigned int height, width, maxValue;
	char magicNumber[3];
	// char comments[100];
}PPMHeader;

typedef struct {
	PPMHeader Header;
	PPMPixel **pixel;
}PPMImage;


clock_t begin, end;

void apply_smoothing(PPMImage *src, PPMImage *dest){

	dest->Header = src->Header;

	/* alocando memoria para imagem destino */
	dest->pixel = (PPMPixel **) calloc (dest->Header.height , sizeof(PPMPixel*));
	for (int i = 0; i < dest->Header.height; i++){
		dest->pixel[i] = (PPMPixel *) calloc (dest->Header.width , sizeof(PPMPixel));
	}

	unsigned int width = dest->Header.width;
	unsigned int height = dest->Header.height;

	for(int i = 0; i < (height); i++){
		for (int j = 0; j < (width); j++){

			/* aplica smoothing no pixel <i,j> */
			/* smoothing 5x5 */
			for (int k = i-2; k < i+3; k++){
				for (int l = j-2; l < j+3; l++){
					if(k > 0 && l > 0 && k < height && l < width){
						dest->pixel[i][j].red += (src->pixel[k][l].red/25);
						dest->pixel[i][j].green += (src->pixel[k][l].green/25);
						dest->pixel[i][j].blue += (src->pixel[k][l].blue/25);
					}
				}
			}
		}
	}

	return;
}

void readImage(FILE *in, PPMImage *dest){
	/*code*/

	unsigned int height;
	unsigned int width;
	PPMPixel aux;


	for (int i = 0; i < dest->Header.height; i++){
		for (int j = 0; j < dest->Header.width; j++){

			/*read image*/
			fscanf(in,"%f",&aux.red);
			fscanf(in,"%f",&aux.green);
			fscanf(in,"%f",&aux.blue);
			dest->pixel[i][j] = aux;
		}
		// cout << j<< endl;
	}

	return;
}



void readHeader(FILE *in,PPMImage *img){
	char magicNumber[3];
	char comments[100];

	unsigned int width, height, maxValue;

	/* lendo magic number: P3 para PPM, P6 para PMM */
	fscanf(in,"%c",&magicNumber[0]);
	fscanf(in,"%c",&magicNumber[1]);
	magicNumber[2] = '\0';

	strcpy(img->Header.magicNumber,magicNumber);

	/* lendo largura e altura */
	fscanf(in,"%d %d",&width,&height);
	img->Header.width = width;
	img->Header.height = height;
	// cout << img->Header.width << "x" << img->Header.height << endl;

	/* alocando imagem PPM (preto) */
	img->pixel = (PPMPixel **) calloc (img->Header.height, sizeof(PPMPixel*));
	for (int i = 0; i < img->Header.height; i++){
		img->pixel[i] = (PPMPixel *) calloc (img->Header.width, sizeof(PPMPixel));
	}

	/* lendo valor maximo */
	fscanf(in,"%d",&maxValue);
	img->Header.maxValue = maxValue;
	// cout << maxValue << endl;

	return ;
}

void writeImage(PPMImage *src, FILE *out){

	out = fopen("output.ppm","wb");
	if(out == NULL){
		cout << "Cannot be opened\n" << endl;
		exit(1);
	}

	fprintf(out, "%s\n", src->Header.magicNumber);
	// fprintf(out, "%s\n", src->Header.comments);
	fprintf(out, "%d %d\n", src->Header.width, src->Header.height);
	fprintf(out, "%d\n", src->Header.maxValue);

	for (int i = 0; i < src->Header.height; i++){
		for (int j = 0; j < src->Header.width; j++){

			fprintf(out, "%d ", (int)src->pixel[i][j].red);
			fprintf(out, "%d ", (int)src->pixel[i][j].green);
			fprintf(out, "%d ", (int)src->pixel[i][j].blue);
		}
			fprintf(out, "\n");
	}

	return ;
}


int main(int argc, char **argv){



	PPMImage *img;
	PPMImage *img_out;
	FILE *input,*output;

	img = (PPMImage*) malloc (sizeof(PPMImage));
	img_out = (PPMImage*) malloc (sizeof(PPMImage));

	input = fopen(argv[1],"rb");
	if(input == NULL){
		cout << "nao abriu" << endl;
		return -1;
	}

	begin = clock();

	cout << "Reading Header...." << endl;
	readHeader(input,img);

	cout << "Reading Image...." << endl;
	readImage(input,img);

	cout << "Applying Smooth...." << endl;
	apply_smoothing(img,img_out);

	cout << "Writing image....";
	writeImage(img_out,output);

	cout << "Done!" << endl;
	fclose(input);

	end = clock();

	double timee = (double) (end-begin) / CLOCKS_PER_SEC;
	printf("tempo: %fs\n",timee);

	return -1;
}
